#pragma once

#include <string>
#include <vector>
#include <memory>
#include <stdexcept>

#include "classfile/class_reader.hpp"

//#include "classfile/attribute_info.hpp"
#include "classfile/constant_info.hpp"
#include "classfile/member_info.h"


namespace jvm {
namespace classfile {

class ClassFile {
public:
    // 静态工厂方法，解析类文件数据
    static std::tuple<std::shared_ptr<ClassFile>, bool> parse(const std::vector<uint8_t>& class_data) {
        try {
            ClassReader reader(class_data);
            auto cf = std::make_shared<ClassFile>();
            cf->read(reader);
            return std::make_tuple(cf, true);
        } catch (const std::exception& e) {
            LOG_ERROR("Parse class file failed: " << std::string(e.what()));
            return std::make_tuple(nullptr, false);
        }
    }

    // Getters
    uint16_t minor_version() const { return _minor_version; }
    uint16_t major_version() const { return _major_version; }
    const ConstantPool& constant_pool() const { return *_constant_pool; }
    uint16_t access_flags() const { return _access_flags; }
    const std::vector<std::shared_ptr<MemberInfo>>& fields() { return _fields; }
    const std::vector<std::shared_ptr<MemberInfo>>& methods() { return _methods; }
    std::shared_ptr<SourceFileAttribute> SourceFileAttribute() const;
    //std::shared_ptr<SourceFileAttribute> SourceFileAttribute();
    std::string getSourceFile() const;
    //std::string getSourceFile();


    // 获取类名、父类名和接口名
    std::string class_name() const;
    std::string super_class_name() const;
    std::vector<std::string> interface_names() const;

private:
    void read(ClassReader& reader);
    void read_and_check_magic(ClassReader& reader);
    void read_and_check_version(ClassReader& reader);

private:
    uint16_t _minor_version = 0;
    uint16_t _major_version = 0;
    std::shared_ptr<ConstantPool> _constant_pool;
    uint16_t _access_flags = 0;
    uint16_t _this_class = 0;
    uint16_t _super_class = 0;
    std::vector<uint16_t> _interfaces;
    std::vector<std::shared_ptr<MemberInfo>> _fields;
    std::vector<std::shared_ptr<MemberInfo>> _methods;
    std::vector<std::shared_ptr<AttributeInfo>> _attributes;
};


inline void ClassFile::read(ClassReader& reader)
{
    read_and_check_magic(reader);
    read_and_check_version(reader);
    _constant_pool = ConstantPool::read_constant_pool(reader);
    LOG_INFO("constant pool count: " << _constant_pool->size());

    _access_flags = reader.read_uint16();
    LOG_INFO("access flags: " << _access_flags);

    _this_class = reader.read_uint16();
    LOG_INFO("this class: " << _this_class);

    _super_class = reader.read_uint16();
    LOG_INFO("super class: " << _super_class);

    _interfaces = reader.read_uint16s();
    LOG_INFO("interfaces count: " << _interfaces.size());

    _fields = MemberInfo::read_members(reader, (*_constant_pool));
    LOG_INFO("fields count: " << _fields.size());

    _methods = MemberInfo::read_members(reader, (*_constant_pool));
    LOG_INFO("methods count: " << _methods.size());
    
    _attributes = readAttributes(&reader, (*_constant_pool));
    LOG_INFO("attributes count: " << _attributes.size());
}


inline void ClassFile::read_and_check_magic(ClassReader& reader)
{
    uint32_t magic = reader.read_uint32();
    LOG_INFO("magic: 0x" << magic);
    if (magic != 0xCAFEBABE)
    {
        LOG_ERROR("Invalid class file magic number: " << magic);
        throw std::runtime_error("java.lang.ClassFormatError: magic!");
    }
}

inline void ClassFile::read_and_check_version(ClassReader& reader)
{
    _minor_version = reader.read_uint16();
    _major_version = reader.read_uint16();
    LOG_INFO("version: " << _major_version << "." <<  _minor_version);
    
    switch (_major_version) {
        case 45:
            return;
        case 46:
        case 47:
        case 48:
        case 49:
        case 50:
        case 51:
        case 52:
        {
            if (_minor_version == 0) {
                return;
            }
        }
        default:
            break;
    }
    
    LOG_ERROR("Unsupported class version: " << _major_version << "." << _minor_version);
    throw std::runtime_error("java.lang.UnsupportedClassVersionError!");
}

inline std::string ClassFile::class_name() const
{
    return _constant_pool->get_class_name(_this_class);
}

inline std::string ClassFile::super_class_name() const
{
    if (_super_class > 0) {
        return _constant_pool->get_class_name(_super_class);
    }
    return "";
}

inline std::vector<std::string> ClassFile::interface_names() const
{
    std::vector<std::string> names;
    names.reserve(_interfaces.size());
    for (uint16_t index : _interfaces) {
        names.push_back(_constant_pool->get_class_name(index));
    }
    return names;
}

inline std::shared_ptr<classfile::SourceFileAttribute> ClassFile::SourceFileAttribute() const
{
    for (const auto& pattr : _attributes)
    {
        if (auto ps = std::dynamic_pointer_cast<classfile::SourceFileAttribute>(pattr))
        {
            return ps;
        }
    }
    return nullptr;
}


inline std::string ClassFile::getSourceFile() const
{
    auto&& psf_attr = SourceFileAttribute();
    if (psf_attr) return psf_attr->getFileName();

    return "Unknown";
}


} // namespace classfile
} // namespace jvm
